package com.fxcharts.widget.linechart;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.*;
import javafx.scene.text.*;

/**
 * @author Aliaksandr_Spichakou
 * Axis line class for ExLine chart
 */
public class ExLineAxis
{
    /**
    * Label for axis
    */
    public-init var label:					String="Axis";
    /*
    * Min value for this axis
    */
    public-init var lowerBound:				Number=0;
    /**
    * Max value for this axis
    */
    public-init var upperBound:				Number=10;
    /**
	*	Tick unit     
    */
    public-init var tickUnit:				Number=1;
    /**
    * Axis color (Default: BLACK)
    */ 
    public-init var axisColor:Color		=	Color.BLACK;
    /**
    * Color for labels 
    */
    public-init var labelColor:Color	=	Color.BLACK;
    
    /**
    * Fill space by color1 and color 2
    */
    public-init var spaceFillColor1:Color =	Color.LIGHTGRAY;
    public-init var spaceFillColor2:Color =	Color.WHITE;
    public-init var showReqLines:Boolean=true;
    
    /**
    * Opacity
    */   
    public-init var opacity:Number		=	1;

    /**
    * Opacity of grid
    */
    public-init var opacityGrid:Number  =	0.5;
    /**
    * Stroke width
    */
    public-init var strokeWidth:Number	=	1;
    /**
    * Font for labels
    */  	
    public-init var font:Font				= Font{	size: 12}
    
    public-init var tickStrings:String[];
    
    /**
    * Start X coordinate for axis line
    */
    protected var zeroX:Number;
    /**
    * Start Y coordinate or axis line
    */
    protected var zeroY:Number;
    /**
    * Axis line length
    */
    protected var length:Number;
    protected var xWidth:Number;
    
    /**
    * Path if axis has is X
    */
    protected var xPath:Path;
    /**
    * Path if axis isY
    */
    protected var yPath:Path;
    
    /**
    * All elements for axis
    */
    protected var group:Group = Group {}  
    
    /**
    * Count of mark points
    */
    var countMarkPoints;
    /**
    * Delta for marks in px.
    */
    var delta;
    
    /**
    * Painting X axis
    */
    protected function paintX():Void
    {
        // create Xpath
        xPath=Path {
            		  translateX: zeroX
            		  translateY: zeroY 
        	          stroke: axisColor
        	          strokeWidth: strokeWidth
        	          opacity: opacity
        	          elements: [
        	              MoveTo {
        	                  x: 0,
        	                  y: 0
        	              },
        	              HLineTo {
        	                  x: length
        	              }
        	          ]
        	      }
        	      
     insert xPath into group.content;
     // prepare painting marks  
     preparePaint();
     
     var i:Number=0;
     
     var coor:Number=0;
     var labelTxt=lowerBound;
      
     // painting marks
     var fillFlag:Boolean=true;  
     while(i<=countMarkPoints)       
     {
         var markPath=Path {
             translateX: zeroX+coor
             translateY: zeroY
             stroke: axisColor
             strokeWidth: strokeWidth
             opacity: opacity
             elements: [
                 MoveTo {
                     x: 0,
                     y: -strokeWidth*2
                 },
                 VLineTo {
                     y: strokeWidth*2
                 }, 
             ]
         }
         
         // paint background rectangl
   	        i++;   	        	
   	        if(i<=countMarkPoints and showReqLines==true)
   	        {
   	              var rq = Rectangle {        	               	    
   	                   	             translateX: zeroX+coor
   	                   	             translateY: 0
   	                   	             width: delta
   	                   	             height: xWidth
   	                   	             opacity: opacityGrid                               	     	                                  
   	                   	             stroke: axisColor
   	                   	             strokeWidth: strokeWidth
   	                 
   	                             } 
   	         if(fillFlag==true)
   	         {
   	            rq.fill=spaceFillColor1;  
   	            fillFlag=false;     	                             	                
   	         }
   	         else
   	         {
   	             rq.fill=spaceFillColor2; 
   	             fillFlag=true;   	   	                       
   	          }
   	          insert rq into group.content;
   	          rq.toBack();   	                 
           	           	             
   	        }
         
         // create label for mark
         var label:Node=createLabelX(labelTxt,zeroX+coor,zeroY+strokeWidth*20, i);
             
         insert markPath into group.content;
         insert label into group.content;        
         coor+=delta;
         labelTxt+=tickUnit;        
     }
	 // create label for axis
	 var axisLabel = createAxisLabelX(zeroX+length/2,zeroY);
	 insert axisLabel into group.content;     
    }
    /**
    * Create axis label if axis is X
    */
    public function createAxisLabelX(translateX:Number, translateY:Number):Node
    {
        var text:Text=Text{
            translateX:translateX
            translateY:translateY                                                 
            font:font
            content: label
        };
        var width = text.boundsInLocal.width;
        var height = text.boundsInLocal.height;
        text.x = -width/2;
        text.y = height*4;
        return text;
    }
    /**
    * Create axis label if axis is Y
    */
    public function createAxisLabelY(translateX:Number, translateY:Number):Node
    {
        var text:Text=Text{
            translateX:translateX
            translateY:translateY                                                 
            font:font
            content: label
            // rotate axis label
            rotate: 270; 
        };
        var width = text.boundsInLocal.width;
        var height = text.boundsInLocal.height;
        text.x = -height*6;
        text.y = width/5;
        return text;
    }
    
    /**
    * Create label for Y marks
    */
    public function createLabelY(value:Object, translateX:Number, translateY:Number, i:Integer):Node
    {
        var label=getLabelValue(value, translateX,translateY, i,true);
        var width = label.boundsInLocal.width;
        var height = label.boundsInLocal.height;
        label.x = -(width+height);
        label.y = height/3;
		return label;                
    }
    
    /**
    * Override this method for custom label
    */
    public function getLabelValue(value:Object, translateX:Number, translateY:Number, i:Integer,isYAxis:Boolean):Text
    {
       var value2Label = value.toString();       
       if(i<=tickStrings.size())
       {
           if(isYAxis==true)
           {
           		value2Label=tickStrings[tickStrings.size()-i];
           }  
           else
           {
            	value2Label=tickStrings[i-1];
           }
       }      
       var label:Text=Text {
                             fill: labelColor
                             translateX: translateX 
                             translateY: translateY                      
                             font: font
                                            
                             content: "{value2Label}";
                        }
        return label; 
    }
    /**
    * Create label for X marks
    */
    public function createLabelX(value:Object, translateX:Number, translateY:Number, i:Integer):Node
    {
        var label=getLabelValue(value, translateX,translateY, i,false);
        var width = label.boundsInLocal.width;
        var height = label.boundsInLocal.height;
        label.x = -width/2;
        //label.y = 2*height;
		return label;                
    }
    
    /**
    * Prepare paintint ticks
    */
    function preparePaint():Void
    {
        // culculate count of mark points
        countMarkPoints=(upperBound-lowerBound)/tickUnit;
        // get module
  	    if(countMarkPoints<0)
  	    {
  	         countMarkPoints*=-1;
  	    }
  	    // delta in px. for every point  	         
  	    delta = length/countMarkPoints;
    }
    
    /**
    * Painting Y axis 
    */
    protected function paintY():Void
    {
	       yPath=Path {
	             	  translateX: zeroX
	                  translateY: zeroY 
	      	          stroke: axisColor
	      	          strokeWidth: strokeWidth
	      	          opacity: opacity
	      	          elements: [	              	             
	      	              MoveTo {
	      	                  x: 0,
	      	                  y: 0
	      	              },
	      	              VLineTo {
	      	                  y: length
	      	              }, 
	      	          ]
	      	      }
      		insert yPath into group.content;
      	   	preparePaint();
  	         
  	         var i:Number=0;
  	         
  	         var coor:Number=0;
  	         var labelTxt=upperBound;
  	         
  	         // painting marks
  	         var fillFlag:Boolean=true;  	        
  	         while(i<=countMarkPoints)       
  	         {
  	             var markPath=Path {
  	                 translateX: zeroX
  	                 translateY: zeroY+coor
  	                 stroke: axisColor
  	                 strokeWidth: strokeWidth
  	                 opacity: opacity
  	                 elements: [
  	                     MoveTo {
  	                         x: -strokeWidth*2,
  	                         y: 0
  	                     },
  	                     HLineTo {
  	                         x: strokeWidth*2
  	                     }, 
  	                 ]
  	             }
  	             // paint background rectangl
  	             i++;
  	             if(i<=countMarkPoints and showReqLines==true)
  	             {
  	              var rq = Rectangle {        	               	    
  	                   	             translateX: zeroX
  	                   	             translateY: coor
  	                   	             width: xWidth
  	                   	             height: delta
  	                   	             opacity: opacityGrid
  	                   	             stroke: axisColor
  	                   	             strokeWidth: strokeWidth
  	                 
  	                                  } 
  	               if(fillFlag)
  	               {
  	                  rq.fill=spaceFillColor1;  
  	                  fillFlag=false;                  	                 
  	               }
  	               else
  	               {
  	                  rq.fill=spaceFillColor2; 
  	                  fillFlag=true;
  	               }
  	               insert rq into group.content;
  	               rq.toBack();   	                 
  	             }
  	              	             
  	             // create labels
   	             var label:Node=createLabelY(labelTxt,zeroX,zeroY+coor, i);
  	           
  	             insert markPath into group.content;
  	             insert label into group.content;  	                
  	             coor+=delta;
  	             labelTxt-=tickUnit;        
  	         }
  	         
  	         var axisLabel = createAxisLabelY(0,zeroY+length/2);  	         
  	         insert axisLabel into group.content;
    }
    
	
}